﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using ExpressionUtil.Parser;
using ExpressionUtil.Extension;
using ExpressionUtil.Node.Common;
using ExpressionUtil.Exceptions;
using System.Runtime.Serialization;

namespace ExpressionUtil.Node
{
    /// <summary>
    /// 扩展函数节点
    /// </summary>
    [Serializable]
    internal class ExtensionFunctionNode : Common.FunctionNode, ISerializable
    {
        /// <summary>
        /// 扩展函数对象
        /// </summary>
        private ExtensionFunction extFunction;

        /// <summary>
        /// 扩展函数执行环境变量
        /// </summary>
        private ExtExecuteContext extContext;

        /// <summary>
        /// 默认构造函数
        /// </summary>
        public ExtensionFunctionNode()
            : base()
        {
            this.extContext = new ExtExecuteContext();
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="info">要填充数据的 System.Runtime.Serialization.SerializationInfo</param>
        /// <param name="context">此序列化的目标</param>
        public ExtensionFunctionNode(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
            throw new NotSupportedException("Extension function serialization ability is not supported.");
        }

        /// <summary>
        /// 执行节点运算
        /// </summary>
        /// <param name="context">执行参数</param>
        /// <returns>执行结果的类型</returns>
        public override ExecuteRunTimeType Execute(ExecuteContext context)
        {
            for (int i = this.Parameters.Count - 1, j = 0; i >= 0; i--, j++)
            {
                ExecuteRunTimeType type = this.Parameters[i].Execute(context);
                if (type == ExecuteRunTimeType.Decimal)
                {
                    this.extContext.Parameters[j].DecimalData = context.GlobalTempNum;
                }
                else if (type == ExecuteRunTimeType.Bool)
                {
                    this.extContext.Parameters[j].BooleanData = context.GlobalTempBool;
                }
                else
                {
                    string msg = string.Format("Extension function parameter runtime type error,function name:{0},parameter count type:{1},parameter count:{2}.",
                        this.extFunction.FunctionName, this.extFunction.ParameterCountType, this.extFunction.ParameterCount);
                    throw new RunTimeTypeErrorException(msg);
                }
            }
            this.extFunction.CallbackHandler(this.extContext);
            if (this.extContext.ReturnValueInfo.Type == ExecuteRunTimeType.Decimal)
            {
                context.GlobalTempNum = this.extContext.ReturnValueInfo.DecimalData;
            }
            else if (this.extContext.ReturnValueInfo.Type == ExecuteRunTimeType.Bool)
            {
                context.GlobalTempBool = this.extContext.ReturnValueInfo.BooleanData;
            }
            else
            {
                string msg = string.Format("Extension function return value runtime type error,function name:{0},parameter count type:{1},parameter count:{2}.",
                    this.extFunction.FunctionName, this.extFunction.ParameterCountType, this.extFunction.ParameterCount);
                throw new RunTimeTypeErrorException(msg);
            }
            return this.extContext.ReturnValueInfo.Type;
        }

        /// <summary>
        /// 创建树节点
        /// </summary>
        /// <param name="context">解析参数</param>
        public static void CreateExtensionFunctionNode(ParseContext context)
        {
            int paramCount = context.FunctionParameterCount.Peek();
            ExtensionFunction func = ParseContext.ExtFunctionMap[context.CurrentExtFunctionName];
            if (func.ParameterCountType == ParameterCountType.Fixed && paramCount != func.ParameterCount)
            {
                throw new FormatException(func.FunctionName + " function parameter count error.");
            }
            if (context.PostfixStack.Count < paramCount)
            {
                throw new FormatException(func.FunctionName + " function missing operand.");
            }
            ExtensionFunctionNode node = new ExtensionFunctionNode();
            node.extFunction = func;
            for (; paramCount > 0; paramCount--)
            {
                node.Parameters.Add(context.PostfixStack.Pop());
                ExtFunctionValueInfo extParam = new ExtFunctionValueInfo();
                node.extContext.Parameters.Add(extParam);
            }
            context.PostfixStack.Push(node);
        }

#if DEBUG
        protected override void DumpCore()
        {
            Debug.WriteLine(string.Format("ExtensionFunctionNode,function name:{0},parameter count type:{1},parameter count:{2},children:", 
                this.extFunction.FunctionName, this.extFunction.ParameterCountType, this.extFunction.ParameterCount));
            for (int i = this.Parameters.Count - 1; i >= 0; i--)
            {
                this.Parameters[i].DumpNode();
            }
        }
#endif

        #region ISerializable 成员
        /// <summary>
        /// 获取对象数据
        /// </summary>
        /// <param name="info">要填充数据的 System.Runtime.Serialization.SerializationInfo</param>
        /// <param name="context">此序列化的目标</param>
        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            throw new NotSupportedException("Extension function serialization ability is not supported.");
        }

        #endregion
    }
}
